import GameBoard from "./game/gameboard";
import {
  ACCELERATE_SPEED,
  HERO_MOVE_SPEED,
  HERO_ROTATE_SPEED,
  INITIAL_ENERGY, MAP_CONFIG, ROTATE_COOL_DOWN
} from "./config/config";
import Weapon from "./weapon";
import HeroSpine from "./hero/heroSpine";
import {globalConfig} from "./config/globalConfig";
import BeKilledBoard from "./result/beKilledBoard";
import {GameMode, GameVar, GlobalObject} from "./game/GameVar";
import {heroFactory} from "./hero/HeroFactory";
import {ballFactory} from "./game/ballFactory";
import {MathUtils} from "./math/MathUtils";
import {frameUpdate} from "./frame/FrameUtils";
import UpdateController from "./frame/UpdateController";

const {ccclass, property} = cc._decorator;

@ccclass
export default class Hero extends cc.Component {

  private _gameBoard: GameBoard;

  @property(cc.Label)
  private txtHeroName: cc.Label = null;

  rotateSpeed: number = 360;

  score: number = 0;

  private _heroMove: boolean = false;

  private weapon: Weapon = null;

  private action: cc.Action;

  energy = 0;

  private _isAccelerate = false;

  private canRotateTimeStamp = 0;

  kill: number = 0;

  continousKill: number = 0;

  beKill: number = 0;

  private _immortal: boolean = false;

  private heroSpine: HeroSpine = null;

  beKilledBoard: cc.Node = null;
  updateController: UpdateController = null;

  private boardScript: BeKilledBoard = null;

  public user: { uid: number, username: string, roleId: number, swimId: number } = {
    uid: -1,
    username: '',
    roleId: 1,
    swimId: 1
  };

  onLoad() {
    this.rotateSpeed = HERO_ROTATE_SPEED;
    this.energy = INITIAL_ENERGY;
    this.weapon = this.node.getComponentInChildren(Weapon)
    this.action = cc.rotateBy(0.2, 360)
    this.heroSpine = this.node.getComponent(HeroSpine);
  }

  start() {
    this.heroSpine.loadRole(this.user.roleId)
    this.heroSpine.loadSwim(this.user.swimId)
  }

  set gameBoard(value: GameBoard) {
    this._gameBoard = value;
    if (this._gameBoard.hero === this.node) {
      this.beKilledBoard = this._gameBoard.beKilledBoard;
      this.boardScript = this.beKilledBoard.getComponent(BeKilledBoard)
    }
  }

  get gameBoard(): GameBoard {
    return this._gameBoard;
  }

  get weaponHeight(): number {
    return this.weapon.node.height
  }

  randomPos() {
    heroFactory.randomPos(this.node)
  }

  realDie() {
    // this._gameBoard.heroPool.put(this.node)
    // if (this._gameBoard.camera.focus === this.node) {
    //     this._gameBoard.changeCameraFocus();
    // }
  }

  reborn() {
    this.randomPos();
    this.enabled = true;
    this.immortal = true;
    this.heroSpine.born();
    this.weapon.setLevel(1)
    this.updateController.addTickFunc(() => {
      this.immortal = false;
    }, 100)
  }

  /**
   * 操作
   */
  accelerate() {
    if (this._isAccelerate) {
      return;
    }
    this._isAccelerate = true;
  }

  /**
   * 操作
   */
  speedToNormal() {
    this._isAccelerate = false;
    this.heroSpine.stopRush();
    // this.motionStreak.enabled = false;
  }

  /**
   * 操作
   */
  rotateSkill() {
    const currentTimestamp = Date.now();
    if (currentTimestamp > this.canRotateTimeStamp) {
      this.canRotateTimeStamp = currentTimestamp + ROTATE_COOL_DOWN * 1000;
      if (this === GameVar.myHero) {
        GlobalObject.voiceSource.playRotate()
      }
      this.node.runAction(this.action)
    }
  }

  /**
   * 操作
   * @param {number} angle
   */
  moveToTargetAngle(angle: number) {
    this.targetAngle = angle;
    this.targetAngle = this.targetAngle % 360;
  }

  /**
   * 操作
   * @param {boolean} value
   */
  set heroMove(value: boolean) {
    if (this._heroMove === value) {
      return;
    }
    this._heroMove = value;
    if (this._heroMove) {
      this.heroSpine.startMarch();
    } else {
      this.heroSpine.stopMarch();
    }
  }

  @frameUpdate()
  updateFixedFrame(dt) {
    if (this._heroMove) {
      this.updateRotation(dt);
      this.updatePosition(dt);
    }
  }

  /**
   * 加分
   * @param {number} score
   */
  addScore(score: number) {
    this.score += score;
    this._gameBoard.rank.updateScore(this.user.uid, this.score)
    this.weapon.checkScore(this.score);
    const e = new cc.Event.EventCustom('score', false)
    e.detail = this.score
    this.node.dispatchEvent(e)
  }

  addEnergy(value: number) {
    this.energy += value;
    if (this.energy > 100) {
      this.energy = 100;
    }
    else if (this.energy < 0) {
      this.energy = 0;
    }
  }

  private updateRotation(dt) {
    //顺时针角度
    let delta = this.targetAngle - this.angle;
    if (delta === 0) {
      // this.state = HeroState.STAND
      return;
    }
    if (delta > 180) {
      delta -= 360;
    } else if (delta < -180) {
      delta += 360
    }
    //逆时针角度旋转
    if (delta < 0) {
      // this.state = HeroState.LEFT
      this.angle -= this.rotateSpeed * dt;
      if (this.angle < this.targetAngle && this.angle > this.targetAngle - this.rotateSpeed * dt) {
        this.angle = this.targetAngle;
      }
    }
    //顺时针角度旋转
    else {
      // this.state = HeroState.RIGHT
      this.angle += this.rotateSpeed * dt;
      if (this.angle > this.targetAngle && this.angle < this.targetAngle + this.rotateSpeed * dt) {
        this.angle = this.targetAngle;
      }
    }
    if (this.angle < 0) {
      this.angle += 360;
    } else if (this.angle > 360) {
      this.angle -= 360
    }
    this.node.rotation = this.angle;
  }

  private angle: number = 0;
  private targetAngle: number = 0;

  private updatePosition(dt) {
    let speed = HERO_MOVE_SPEED;
    if (this._isAccelerate && this.energy > 0) {
      speed = ACCELERATE_SPEED;
      this.addEnergy(Math.floor(-globalConfig.base_config.speedcost * dt))
      if (this.user.uid === GameVar.userInfo.uid) {
        GlobalObject.voiceSource.playAcc();
      }
      this.heroSpine.startRush()
    } else {
      if (this.user.uid === GameVar.userInfo.uid) {
        GlobalObject.voiceSource.stopAcc();
      }
      this.heroSpine.stopRush()
    }
    const speedX = speed * MathUtils.sin(this.angle);
    const speedY = speed * MathUtils.cos(this.angle);
    this.node.x = (this.node.x + speedX * dt)
    this.node.y = (this.node.y + speedY * dt)
    if (this.checkBound()) {
      this.node.emit('reachBound')
    }
  }

  public checkBound() {
    let flag = false;
    if (this.node.x < MAP_CONFIG.startx) {
      this.node.x = MAP_CONFIG.startx;
      flag = true
    } else if (this.node.x > MAP_CONFIG.startx + MAP_CONFIG.width) {
      this.node.x = MAP_CONFIG.startx + MAP_CONFIG.width
      flag = true
    }
    if (this.node.y < MAP_CONFIG.starty) {
      this.node.y = MAP_CONFIG.starty;
      flag = true
    }
    else if (this.node.y > MAP_CONFIG.starty + MAP_CONFIG.height) {
      this.node.y = MAP_CONFIG.starty + MAP_CONFIG.height
      flag = true
    }
    return flag
  }

  get heroMove(): boolean {
    return this._heroMove;
  }

  private killUsername: string = ""

  beHit(name: string) {
    this.killUsername = name;
    this.enabled = false;
    if (GameVar.mode === GameMode.LIMITED) {
      this.addScore(-this.score)
    }
    this.beKill++;
    this.continousKill = 0;
    this._immortal = true;
    this.heroSpine.die()
    this.updateController.addTickFunc(() => {
      if (this.user.uid === GameVar.userInfo.uid) {
        this.showKilled();
      } else {
        this.reborn();
      }
    }, 40)
    this.dropBubble();
  }

  private dropBubble() {
    const count = this.getBubbleCount();
    for (let i = 0; i < count; i++) {
      const bubble = ballFactory.create();
      bubble.node.x = this.node.x;
      bubble.node.y = this.node.y;
      bubble.launch();
    }
  }

  private getBubbleCount() {
    if (this.score < 50) {
      return 5;
    }
    if (this.score < 200) {
      return 6;
    }
    if (this.score < 350) {
      return 7;
    }
    if (this.score < 500) {
      return 8
    }
    if (this.score < 750) {
      return 9
    }
    return 10;
  }

  showKilled() {
    if (GameVar.mode === GameMode.LIMITED) {
      this.boardScript.show(this.killUsername, () => {
        GlobalObject.voiceSource.playRevive();
        this.reborn()
      })
    } else {
      this._gameBoard.onInfiGameEnd();
    }
  }

  public addKill(count: number = 1) {
    this.kill += count;
    this.continousKill += count;
    let kill = this.continousKill;
    if (kill > 10) {
      kill = 10
    }
    const config: any = globalConfig.point_config[kill - 1]
    if (config) {
      //加分
      const score = config.extrapoint;
      this.addScore(score)
    }
    //派发 kill event
    const e = new cc.Event.EventCustom('kill', false)
    e.detail = this.kill
    this.node.dispatchEvent(e)
    const e1 = new cc.Event.EventCustom('continousKill', false)
    e1.detail = this.continousKill
    this.node.dispatchEvent(e1)
  }

  public getRank(): number {
    return this.gameBoard.rank.getRankById(this.user.uid);
  }

  private _state: HeroState = 0

  set state(value: HeroState) {
    if (this._state === value) {
      return
    }
    switch (value) {
      case HeroState.STAND:
        this.heroSpine.stand();
        break
      case HeroState.LEFT:
        this.heroSpine.left();
        break
      case HeroState.RIGHT:
        this.heroSpine.right();
        break
    }
    this._state = value;
  }


  get immortal(): boolean {
    return this._immortal;
  }

  set immortal(value: boolean) {
    if (value) {
      this.node.opacity = 128
    } else {
      this.node.opacity = 255
    }
    this._immortal = value;
  }

  get isAccelerate(): boolean {
    return this._isAccelerate;
  }
}

enum HeroState {
  STAND,
  LEFT,
  RIGHT
}
